<template>
	<view
		:class="[
			'input-number',
			rigth ? 'rigth' : '',
			disabled ? 'disabled' : ''
		]"
		:style="{ width: width + 'rpx', height: height + 'rpx' }"
	>
		<text class="first-text" @tap="reduceValue">-</text>
		<text class="last-text" @tap="addValue">+</text>
		<view class="input-box">
			<input
				ref="input"
				type="number"
				:value="value"
				:disabled="disabled"
				@blur="valueBlurEvent"
			/>
		</view>
	</view>
</template>

<script>
export default {
	emits: ['update:value', 'change'],
	props: {
		// 宽
		width: {
			type: String,
			require: true,
			default: '186'
		},
		// 高
		height: {
			type: String,
			require: true,
			default: '48'
		},
		// 双向绑定值
		value: {
			type: Number,
			require: true,
			default: 0
		},
		// 最小值
		min: {
			type: Number,
			require: false,
			default: null
		},
		// 最小值提示信息
		minTip: {
			type: String,
			require: false,
			default: null
		},
		// 最大值
		max: {
			type: Number,
			require: false,
			default: null
		},
		// 最大值提示信息
		maxTip: {
			type: String,
			require: false,
			default: null
		},
		// 按钮位置
		rigth: {
			type: Boolean,
			require: false,
			default: false
		},
		// 增长倍数
		step: {
			type: Number,
			require: false,
			default: null
		},
		// 是否禁用 默认不禁用
		disabled: {
			type: Boolean,
			require: false,
			default: false
		},
		// 间隔时间
		interval: {
			type: Number,
			require: false,
			default: 200
		}
	},
	data() {
		return {
			lock: false
		};
	},
	methods: {
		// 限制函数
		throttle(fn, time = 500) {
			const _this = this;
			return function() {
				const args = arguments; // 获取参数
				if (_this.lock) {
					return;
				}
				_this.lock = true;
				setTimeout(() => {
					_this.lock = false;
				}, time);
				fn.apply(_this, args);
			};
		},
		// 点击添加
		addValue() {
			this.throttle(() => {
				if (this.disabled) {
					return;
				}
				if (!this.vaiMax(this.value)) {
					return;
				}
				this.$emit('update:value', this.stepValue(true, this.value));
				this.$emit('change', this.stepValue(true, this.value));
			}, this.interval)();
		},
		reduceValue() {
			this.throttle(() => {
				if (this.disabled) {
					return;
				}
				if (!this.vaiMin(this.value)) {
					return;
				}
				this.$emit('update:value', this.stepValue(false, this.value));
				this.$emit('change', this.stepValue(false, this.value));
			}, this.interval)();
		},
		// 验证最大值
		vaiMax(value, isStep = true) {
			// 是否存在 最大值
			if (this.max === null) {
				return true;
			}

			const step = this.step ? this.step : 1;
			if (isStep) {
				value += step;
			}
			if (value > this.max) {
				uni.showToast({
					title: this.maxTip ?? '不能超过最大数量',
					icon: 'error'
				});
				return false;
			}
			return true;
		},
		// 验证最小值
		vaiMin(value, isStep = true) {
			if (!this.disabled) {
				if (this.min === null) {
					return true;
				}
				const step = this.step ? this.step : 1;
				if (isStep) {
					value -= step;
				}
				if (value < this.min) {
					uni.showToast({
						title: this.maxTip ?? '不能小于最小数量',
						icon: 'error'
					});
					return false;
				}

				return true;
			}
		},
		// 倍数增加 减少
		stepValue(isAdd, value) {
			if (!this.disabled) {
				if (this.step === null) {
					return isAdd ? value + 1 : value - 1;
				}
				if (isAdd) {
					value = value + this.step;
				} else {
					value = value - this.step;
				}

				return value;
			}
		},
		// change 事件
		valueBlurEvent($event) {
			let value = Number($event.detail.value);
			if (value === this.value) {
				return;
			}

			value = this.stepChange(value);

			this.$emit('update:value', value);
			this.$emit('change', value);
		},
		// 倍数增长
		stepChange(value) {
			if (!this.vaiMax(value, false)) {
				return this.max;
			}
			if (!this.vaiMin(value, false)) {
				return this.min;
			}
			if (this.step === null) {
				return value;
			}
			if (value <= this.step) {
				return this.min || this.step;
			}
			const par = value % this.step;
			if (par !== 0) {
				const com = value + this.step - par;
				if (this.max && this.max < com) {
					return value - par;
				}
				if (this.min && com <= this.min) {
					return this.min;
				}
				return com;
			}
			return value;
		}
	}
};
</script>

<style lang="scss" scoped>
.input-number {
	display: inline-block;
	width: 186rpx;
	height: 48rpx;
	margin: auto;
	position: relative;
	border-radius: 6rpx;
	border: 2rpx solid #e1e9ef;
	box-sizing: border-box;

	> text {
		width: 25%;
		height: 100%;
		position: absolute;
		text-align: center;
		cursor: pointer;
		display: flex;
		align-items: center;
		justify-content: center;
		background: #fff;
	}

	> .first-text {
		top: 0;
		left: 0;
		border-right: 2rpx solid #e1e9ef;
	}

	> .last-text {
		top: 0;
		right: 0;
		border-left: 2rpx solid #e1e9ef;
	}

	.input-box {
		height: 100%;
		display: flex;
		align-items: center;
		justify-content: center;
		background-color: #fff;
		input::-webkit-outer-spin-button,
		input::-webkit-inner-spin-button {
			-webkit-appearance: none;
			-moz-appearance: textfield;
			appearance: none;
		}
		> input {
			width: 33%;
			height: 100%;
			text-align: center;
			font-size: 28rpx;
			outline: none;
			border: none;
		}
	}
}

.disabled {
	> span {
		background: #ededed;
	}
}

.rigth {
	> text {
		height: 50%;
	}

	> text:first-of-type {
		top: inherit;
		left: inherit;
		right: -2rpx;
		bottom: 0;
		border-left: 2rpx solid #e1e9ef;
	}

	> text:last-of-type {
		right: 0;
		border-bottom: 2rpx solid #e1e9ef;
	}

	.input-box {
		justify-content: flex-start;
		> input {
			width: 75%;
			border-left: none;
		}
	}
}
</style>
